@@ -21,12 +21,12 @@ class AgentsController < ApplicationController |
||
21 | 21 |
end |
22 | 22 |
|
23 | 23 |
def run |
24 |
- agent = current_user.agents.find(params[:id]) |
|
25 |
- Agent.async_check(agent.id) |
|
26 |
- if params[:return] == "show" |
|
27 |
- redirect_to agent_path(agent), notice: "Agent run queued" |
|
28 |
- else |
|
29 |
- redirect_to agents_path, notice: "Agent run queued" |
|
24 |
+ @agent = current_user.agents.find(params[:id]) |
|
25 |
+ Agent.async_check(@agent.id) |
|
26 |
+ |
|
27 |
+ respond_to do |format| |
|
28 |
+ format.html { redirect_back "Agent run queued for '#{@agent.name}'" } |
|
29 |
+ format.json { head :ok } |
|
30 | 30 |
end |
31 | 31 |
end |
32 | 32 |
|
@@ -53,12 +53,20 @@ class AgentsController < ApplicationController |
||
53 | 53 |
def remove_events |
54 | 54 |
@agent = current_user.agents.find(params[:id]) |
55 | 55 |
@agent.events.delete_all |
56 |
- redirect_to agents_path, notice: "All events removed" |
|
56 |
+ |
|
57 |
+ respond_to do |format| |
|
58 |
+ format.html { redirect_back "All emitted events removed for '#{@agent.name}'" } |
|
59 |
+ format.json { head :ok } |
|
60 |
+ end |
|
57 | 61 |
end |
58 | 62 |
|
59 | 63 |
def propagate |
60 |
- details = Agent.receive! |
|
61 |
- redirect_to agents_path, notice: "Queued propagation calls for #{details[:event_count]} event(s) on #{details[:agent_count]} agent(s)" |
|
64 |
+ details = Agent.receive! # Eventually this should probably be scoped to the current_user. |
|
65 |
+ |
|
66 |
+ respond_to do |format| |
|
67 |
+ format.html { redirect_back "Queued propagation calls for #{details[:event_count]} event(s) on #{details[:agent_count]} agent(s)" } |
|
68 |
+ format.json { head :ok } |
|
69 |
+ end |
|
62 | 70 |
end |
63 | 71 |
|
64 | 72 |
def show |
@@ -99,8 +107,8 @@ class AgentsController < ApplicationController |
||
99 | 107 |
params[:agent]) |
100 | 108 |
respond_to do |format| |
101 | 109 |
if @agent.save |
102 |
- format.html { redirect_to agents_path, notice: 'Your Agent was successfully created.' } |
|
103 |
- format.json { render json: @agent, status: :created, location: @agent } |
|
110 |
+ format.html { redirect_back "'#{@agent.name}' was successfully created." } |
|
111 |
+ format.json { render json: @agent, status: :ok, location: agent_path(@agent) } |
|
104 | 112 |
else |
105 | 113 |
format.html { render action: "new" } |
106 | 114 |
format.json { render json: @agent.errors, status: :unprocessable_entity } |
@@ -113,14 +121,8 @@ class AgentsController < ApplicationController |
||
113 | 121 |
|
114 | 122 |
respond_to do |format| |
115 | 123 |
if @agent.update_attributes(params[:agent]) |
116 |
- format.html { |
|
117 |
- if params[:return] == "show" |
|
118 |
- redirect_to agent_path(@agent), notice: 'Your Agent was successfully updated.' |
|
119 |
- else |
|
120 |
- redirect_to agents_path, notice: 'Your Agent was successfully updated.' |
|
121 |
- end |
|
122 |
- } |
|
123 |
- format.json { head :no_content } |
|
124 |
+ format.html { redirect_back "'#{@agent.name}' was successfully updated." } |
|
125 |
+ format.json { render json: @agent, status: :ok, location: agent_path(@agent) } |
|
124 | 126 |
else |
125 | 127 |
format.html { render action: "edit" } |
126 | 128 |
format.json { render json: @agent.errors, status: :unprocessable_entity } |
@@ -133,8 +135,23 @@ class AgentsController < ApplicationController |
||
133 | 135 |
@agent.destroy |
134 | 136 |
|
135 | 137 |
respond_to do |format| |
136 |
- format.html { redirect_to agents_path } |
|
138 |
+ format.html { redirect_back "'#{@agent.name}' deleted" } |
|
137 | 139 |
format.json { head :no_content } |
138 | 140 |
end |
139 | 141 |
end |
142 |
+ |
|
143 |
+ protected |
|
144 |
+ |
|
145 |
+ # Sanitize params[:return] to prevent open redirect attacks, a common security issue. |
|
146 |
+ def redirect_back(message) |
|
147 |
+ if params[:return] == "show" && @agent |
|
148 |
+ path = agent_path(@agent) |
|
149 |
+ elsif params[:return] =~ /\A#{Regexp::escape scenarios_path}\/\d+\Z/ |
|
150 |
+ path = params[:return] |
|
151 |
+ else |
|
152 |
+ path = agents_path |
|
153 |
+ end |
|
154 |
+ |
|
155 |
+ redirect_to path, notice: message |
|
156 |
+ end |
|
140 | 157 |
end |
@@ -31,11 +31,11 @@ |
||
31 | 31 |
|
32 | 32 |
<% if agent.can_create_events? && agent.events.count > 0 %> |
33 | 33 |
<li> |
34 |
- <%= link_to '<span class="color-danger glyphicon glyphicon-trash"></span> Delete all events'.html_safe, remove_events_agent_path(agent), method: :delete, data: {confirm: 'Are you sure you want to delete ALL emitted events for this Agent?'}, :tabindex => "-1" %> |
|
34 |
+ <%= link_to '<span class="color-danger glyphicon glyphicon-trash"></span> Delete all events'.html_safe, remove_events_agent_path(agent, :return => returnTo), method: :delete, data: {confirm: 'Are you sure you want to delete ALL emitted events for this Agent?'}, :tabindex => "-1" %> |
|
35 | 35 |
</li> |
36 | 36 |
<% end %> |
37 | 37 |
|
38 | 38 |
<li> |
39 |
- <%= link_to '<span class="color-danger glyphicon glyphicon-remove"></span> Delete agent'.html_safe, agent_path(agent), method: :delete, data: { confirm: 'Are you sure that you want to permanently delete this Agent?' }, :tabindex => "-1" %> |
|
39 |
+ <%= link_to '<span class="color-danger glyphicon glyphicon-remove"></span> Delete agent'.html_safe, agent_path(agent, :return => returnTo), method: :delete, data: { confirm: 'Are you sure that you want to permanently delete this Agent?' }, :tabindex => "-1" %> |
|
40 | 40 |
</li> |
41 | 41 |
</ul> |
@@ -64,7 +64,7 @@ |
||
64 | 64 |
<button type="button" class="btn btn-default btn-sm dropdown-toggle" data-toggle="dropdown"> |
65 | 65 |
<span class="glyphicon glyphicon-th-list"></span> Actions <span class="caret"></span> |
66 | 66 |
</button> |
67 |
- <%= render 'agents/action_menu', :agent => agent, :returnTo => "index" %> |
|
67 |
+ <%= render 'agents/action_menu', :agent => agent, :returnTo => (defined?(returnTo) && returnTo) || "index" %> |
|
68 | 68 |
</div> |
69 | 69 |
</td> |
70 | 70 |
</tr> |
@@ -5,7 +5,7 @@ |
||
5 | 5 |
<h2>Your Agents</h2> |
6 | 6 |
</div> |
7 | 7 |
|
8 |
- <%= render :partial => 'agents/table' %> |
|
8 |
+ <%= render 'agents/table' %> |
|
9 | 9 |
|
10 | 10 |
<br/> |
11 | 11 |
|
@@ -15,7 +15,7 @@ |
||
15 | 15 |
<h3>Agents</h3> |
16 | 16 |
</div> |
17 | 17 |
|
18 |
- <%= render :partial => 'agents/table' %> |
|
18 |
+ <%= render 'agents/table', :returnTo => scenario_path(@scenario) %> |
|
19 | 19 |
</div> |
20 | 20 |
</div> |
21 | 21 |
</div> |
@@ -34,6 +34,47 @@ describe AgentsController do |
||
34 | 34 |
end |
35 | 35 |
end |
36 | 36 |
|
37 |
+ describe "POST run" do |
|
38 |
+ it "triggers Agent.async_check with the Agent's ID" do |
|
39 |
+ sign_in users(:bob) |
|
40 |
+ mock(Agent).async_check(agents(:bob_manual_event_agent).id) |
|
41 |
+ post :run, :id => agents(:bob_manual_event_agent).to_param |
|
42 |
+ end |
|
43 |
+ |
|
44 |
+ it "can only be accessed by the Agent's owner" do |
|
45 |
+ sign_in users(:jane) |
|
46 |
+ lambda { |
|
47 |
+ post :run, :id => agents(:bob_manual_event_agent).to_param |
|
48 |
+ }.should raise_error(ActiveRecord::RecordNotFound) |
|
49 |
+ end |
|
50 |
+ end |
|
51 |
+ |
|
52 |
+ describe "POST remove_events" do |
|
53 |
+ it "deletes all events created by the given Agent" do |
|
54 |
+ sign_in users(:bob) |
|
55 |
+ agent_event = events(:bob_website_agent_event).id |
|
56 |
+ other_event = events(:jane_website_agent_event).id |
|
57 |
+ post :remove_events, :id => agents(:bob_website_agent).to_param |
|
58 |
+ Event.where(:id => agent_event).count.should == 0 |
|
59 |
+ Event.where(:id => other_event).count.should == 1 |
|
60 |
+ end |
|
61 |
+ |
|
62 |
+ it "can only be accessed by the Agent's owner" do |
|
63 |
+ sign_in users(:jane) |
|
64 |
+ lambda { |
|
65 |
+ post :remove_events, :id => agents(:bob_website_agent).to_param |
|
66 |
+ }.should raise_error(ActiveRecord::RecordNotFound) |
|
67 |
+ end |
|
68 |
+ end |
|
69 |
+ |
|
70 |
+ describe "POST propagate" do |
|
71 |
+ it "runs event propagation for all Agents" do |
|
72 |
+ sign_in users(:bob) |
|
73 |
+ mock.proxy(Agent).receive! |
|
74 |
+ post :propagate |
|
75 |
+ end |
|
76 |
+ end |
|
77 |
+ |
|
37 | 78 |
describe "GET show" do |
38 | 79 |
it "only shows Agents for the current user" do |
39 | 80 |
sign_in users(:bob) |
@@ -152,6 +193,14 @@ describe AgentsController do |
||
152 | 193 |
}.should raise_error(ActiveRecord::RecordNotFound) |
153 | 194 |
end |
154 | 195 |
|
196 |
+ it "accepts JSON requests" do |
|
197 |
+ sign_in users(:bob) |
|
198 |
+ post :update, :id => agents(:bob_website_agent).to_param, :agent => valid_attributes(:name => "New name"), :format => :json |
|
199 |
+ agents(:bob_website_agent).reload.name.should == "New name" |
|
200 |
+ JSON.parse(response.body)['name'].should == "New name" |
|
201 |
+ response.should be_success |
|
202 |
+ end |
|
203 |
+ |
|
155 | 204 |
it "will not accept Agent sources owned by other users" do |
156 | 205 |
sign_in users(:bob) |
157 | 206 |
post :update, :id => agents(:bob_website_agent).to_param, :agent => valid_attributes(:source_ids => [agents(:jane_weather_agent).id]) |
@@ -164,6 +213,38 @@ describe AgentsController do |
||
164 | 213 |
assigns(:agent).should have(1).errors_on(:name) |
165 | 214 |
response.should render_template("edit") |
166 | 215 |
end |
216 |
+ |
|
217 |
+ describe "redirecting back" do |
|
218 |
+ before do |
|
219 |
+ sign_in users(:bob) |
|
220 |
+ end |
|
221 |
+ |
|
222 |
+ it "can redirect back to the show path" do |
|
223 |
+ post :update, :id => agents(:bob_website_agent).to_param, :agent => valid_attributes(:name => "New name"), :return => "show" |
|
224 |
+ response.should redirect_to(agent_path(agents(:bob_website_agent))) |
|
225 |
+ end |
|
226 |
+ |
|
227 |
+ it "redirect back to the index path by default" do |
|
228 |
+ post :update, :id => agents(:bob_website_agent).to_param, :agent => valid_attributes(:name => "New name") |
|
229 |
+ response.should redirect_to(agents_path) |
|
230 |
+ end |
|
231 |
+ |
|
232 |
+ it "accepts return paths to scenarios" do |
|
233 |
+ post :update, :id => agents(:bob_website_agent).to_param, :agent => valid_attributes(:name => "New name"), :return => "/scenarios/2" |
|
234 |
+ response.should redirect_to("/scenarios/2") |
|
235 |
+ end |
|
236 |
+ |
|
237 |
+ it "sanitizes return paths" do |
|
238 |
+ post :update, :id => agents(:bob_website_agent).to_param, :agent => valid_attributes(:name => "New name"), :return => "/scenar" |
|
239 |
+ response.should redirect_to(agents_path) |
|
240 |
+ |
|
241 |
+ post :update, :id => agents(:bob_website_agent).to_param, :agent => valid_attributes(:name => "New name"), :return => "http://google.com" |
|
242 |
+ response.should redirect_to(agents_path) |
|
243 |
+ |
|
244 |
+ post :update, :id => agents(:bob_website_agent).to_param, :agent => valid_attributes(:name => "New name"), :return => "javascript:alert(1)" |
|
245 |
+ response.should redirect_to(agents_path) |
|
246 |
+ end |
|
247 |
+ end |
|
167 | 248 |
end |
168 | 249 |
|
169 | 250 |
describe "DELETE destroy" do |